import mongoose, { Document, Model, Schema } from 'mongoose';

/**
 * Session接口定义
 * 定义会话的基本属性
 */
export interface ISession {
  sessionId: string;           // Session ID（唯一）
  userId: mongoose.Types.ObjectId;  // 用户ID
  userAgent?: string;          // 用户代理
  ipAddress: string;           // IP地址
  loginTime: Date;             // 登录时间
  lastAccessTime: Date;        // 最后访问时间
  expiresAt: Date;             // 过期时间
  isActive: boolean;           // 是否活跃
  systemId?: mongoose.Types.ObjectId;  // 关联的子系统ID（可选）
  parentSessionId?: string;    // 父会话ID（SSO主会话）
  sessionType: 'master' | 'slave';  // 会话类型：master/slave
  syncedSystems: mongoose.Types.ObjectId[];  // 已同步的子系统列表
}

/**
 * Session文档接口
 * 继承ISession和mongoose.Document
 */
export interface ISessionDocument extends ISession, Document {
  /**
   * 转换为JSON格式
   * @returns 格式化的会话信息
   */
  toJSON(): any;

  /**
   * 检查会话是否过期
   * @returns 是否过期
   */
  isExpired(): boolean;

  /**
   * 更新最后访问时间
   * @returns Promise<ISessionDocument>
   */
  updateLastAccess(): Promise<ISessionDocument>;

  /**
   * 添加同步的子系统
   * @param systemId 子系统ID
   * @returns Promise<ISessionDocument>
   */
  addSyncedSystem(systemId: mongoose.Types.ObjectId): Promise<ISessionDocument>;

  /**
   * 移除同步的子系统
   * @param systemId 子系统ID
   * @returns Promise<ISessionDocument>
   */
  removeSyncedSystem(systemId: mongoose.Types.ObjectId): Promise<ISessionDocument>;
}

/**
 * Session模型接口
 * 定义静态方法
 */
export interface ISessionModel extends Model<ISessionDocument> {
  /**
   * 根据sessionId查找会话
   * @param sessionId 会话ID
   * @returns Promise<ISessionDocument | null>
   */
  findBySessionId(sessionId: string): Promise<ISessionDocument | null>;

  /**
   * 根据用户ID查找活跃会话
   * @param userId 用户ID
   * @returns Promise<ISessionDocument[]>
   */
  findActiveByUserId(userId: mongoose.Types.ObjectId): Promise<ISessionDocument[]>;

  /**
   * 根据用户ID查找主会话
   * @param userId 用户ID
   * @returns Promise<ISessionDocument | null>
   */
  findMasterByUserId(userId: mongoose.Types.ObjectId): Promise<ISessionDocument | null>;

  /**
   * 根据父会话ID查找子会话
   * @param parentSessionId 父会话ID
   * @returns Promise<ISessionDocument[]>
   */
  findSlavesByParentId(parentSessionId: string): Promise<ISessionDocument[]>;

  /**
   * 清理过期会话
   * @returns Promise<number> 清理的会话数量
   */
  cleanExpiredSessions(): Promise<number>;

  /**
   * 根据系统ID查找会话
   * @param systemId 系统ID
   * @returns Promise<ISessionDocument[]>
   */
  findBySystemId(systemId: mongoose.Types.ObjectId): Promise<ISessionDocument[]>;

  /**
   * 使用户的所有会话失效
   * @param userId 用户ID
   * @returns Promise<number> 失效的会话数量
   */
  invalidateUserSessions(userId: mongoose.Types.ObjectId): Promise<number>;
}

/**
 * Session Schema定义
 */
const SessionSchema = new Schema<ISessionDocument>({
  sessionId: {
    type: String,
    required: [true, 'Session ID是必需的'],
    unique: true,
    index: true,
    trim: true
  },
  userId: {
    type: Schema.Types.ObjectId,
    ref: 'User',
    required: [true, '用户ID是必需的'],
    index: true
  },
  userAgent: {
    type: String,
    trim: true,
    maxlength: [500, '用户代理信息不能超过500个字符']
  },
  ipAddress: {
    type: String,
    required: [true, 'IP地址是必需的'],
    trim: true,
    validate: {
      validator: function(v: string) {
        // IP地址验证（支持IPv4、IPv6和IPv4映射的IPv6地址）
        const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
        const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
        const ipv4MappedIpv6Regex = /^::ffff:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
        const compressedIpv6Regex = /^([0-9a-fA-F]{0,4}:){1,7}:([0-9a-fA-F]{0,4}:){0,6}[0-9a-fA-F]{0,4}$/;
        return ipv4Regex.test(v) || ipv6Regex.test(v) || ipv4MappedIpv6Regex.test(v) || compressedIpv6Regex.test(v);
      },
      message: 'IP地址格式不正确'
    }
  },
  loginTime: {
    type: Date,
    required: [true, '登录时间是必需的'],
    default: Date.now
  },
  lastAccessTime: {
    type: Date,
    required: [true, '最后访问时间是必需的'],
    default: Date.now,
    index: true
  },
  expiresAt: {
    type: Date,
    required: [true, '过期时间是必需的'],
    index: true
  },
  isActive: {
    type: Boolean,
    required: true,
    default: true,
    index: true
  },
  systemId: {
    type: Schema.Types.ObjectId,
    ref: 'System',
    index: true
  },
  parentSessionId: {
    type: String,
    trim: true,
    index: true
  },
  sessionType: {
    type: String,
    required: [true, '会话类型是必需的'],
    enum: {
      values: ['master', 'slave'],
      message: '会话类型必须是master或slave'
    },
    default: 'master',
    index: true
  },
  syncedSystems: [{
    type: Schema.Types.ObjectId,
    ref: 'System'
  }]
}, {
  timestamps: true,
  versionKey: false,
  collection: 'sessions'
});

// 创建复合索引
SessionSchema.index({ userId: 1, isActive: 1 });
SessionSchema.index({ sessionType: 1, isActive: 1 });
SessionSchema.index({ parentSessionId: 1, sessionType: 1 });
SessionSchema.index({ systemId: 1, isActive: 1 });
SessionSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 }); // TTL索引，自动删除过期文档

// 保存前中间件
SessionSchema.pre('save', function(next) {
  // 如果是新文档或者lastAccessTime被修改，更新lastAccessTime
  if (this.isNew || this.isModified('lastAccessTime')) {
    this.lastAccessTime = new Date();
  }
  
  // 验证会话类型和父会话ID的关系
  if (this.sessionType === 'slave' && !this.parentSessionId) {
    return next(new Error('从会话必须有父会话ID'));
  }
  
  if (this.sessionType === 'master' && this.parentSessionId) {
    return next(new Error('主会话不能有父会话ID'));
  }
  
  next();
});

// 更新前中间件
SessionSchema.pre('findOneAndUpdate', function(next) {
  // 自动更新lastAccessTime
  this.set({ lastAccessTime: new Date() });
  next();
});

// 实例方法：转换为JSON
SessionSchema.methods.toJSON = function() {
  const session = this.toObject();
  
  // 移除敏感信息
  delete session.__v;
  
  return {
    id: session._id,
    sessionId: session.sessionId,
    userId: session.userId,
    userAgent: session.userAgent,
    ipAddress: session.ipAddress,
    loginTime: session.loginTime,
    lastAccessTime: session.lastAccessTime,
    expiresAt: session.expiresAt,
    isActive: session.isActive,
    systemId: session.systemId,
    parentSessionId: session.parentSessionId,
    sessionType: session.sessionType,
    syncedSystems: session.syncedSystems,
    createdAt: session.createdAt,
    updatedAt: session.updatedAt
  };
};

// 实例方法：检查会话是否过期
SessionSchema.methods.isExpired = function(): boolean {
  return new Date() > this.expiresAt;
};

// 实例方法：更新最后访问时间
SessionSchema.methods.updateLastAccess = function(): Promise<ISessionDocument> {
  this.lastAccessTime = new Date();
  return this.save();
};

// 实例方法：添加同步的子系统
SessionSchema.methods.addSyncedSystem = function(systemId: mongoose.Types.ObjectId): Promise<ISessionDocument> {
  if (!this.syncedSystems.includes(systemId)) {
    this.syncedSystems.push(systemId);
  }
  return this.save();
};

// 实例方法：移除同步的子系统
SessionSchema.methods.removeSyncedSystem = function(systemId: mongoose.Types.ObjectId): Promise<ISessionDocument> {
  this.syncedSystems = this.syncedSystems.filter((id: mongoose.Types.ObjectId) => !id.equals(systemId));
  return this.save();
};

// 静态方法：根据sessionId查找会话
SessionSchema.statics.findBySessionId = function(sessionId: string): Promise<ISessionDocument | null> {
  return this.findOne({ sessionId, isActive: true }).populate('userId', 'username email realName');
};

// 静态方法：根据用户ID查找活跃会话
SessionSchema.statics.findActiveByUserId = function(userId: mongoose.Types.ObjectId): Promise<ISessionDocument[]> {
  return this.find({ 
    userId, 
    isActive: true,
    expiresAt: { $gt: new Date() }
  }).sort({ lastAccessTime: -1 });
};

// 静态方法：根据用户ID查找主会话
SessionSchema.statics.findMasterByUserId = function(userId: mongoose.Types.ObjectId): Promise<ISessionDocument | null> {
  return this.findOne({ 
    userId, 
    sessionType: 'master',
    isActive: true,
    expiresAt: { $gt: new Date() }
  }).sort({ lastAccessTime: -1 });
};

// 静态方法：根据父会话ID查找子会话
SessionSchema.statics.findSlavesByParentId = function(parentSessionId: string): Promise<ISessionDocument[]> {
  return this.find({ 
    parentSessionId,
    sessionType: 'slave',
    isActive: true,
    expiresAt: { $gt: new Date() }
  }).sort({ lastAccessTime: -1 });
};

// 静态方法：清理过期会话
SessionSchema.statics.cleanExpiredSessions = function(): Promise<number> {
  return this.updateMany(
    { 
      $or: [
        { expiresAt: { $lt: new Date() } },
        { isActive: false }
      ]
    },
    { isActive: false }
  ).then((result: any) => result.modifiedCount);
};

// 静态方法：根据系统ID查找会话
SessionSchema.statics.findBySystemId = function(systemId: mongoose.Types.ObjectId): Promise<ISessionDocument[]> {
  return this.find({ 
    systemId,
    isActive: true,
    expiresAt: { $gt: new Date() }
  }).sort({ lastAccessTime: -1 });
};

// 静态方法：使用户的所有会话失效
SessionSchema.statics.invalidateUserSessions = function(userId: mongoose.Types.ObjectId): Promise<number> {
  return this.updateMany(
    { userId, isActive: true },
    { isActive: false }
  ).then((result: any) => result.modifiedCount);
};

// 创建并导出模型
export const Session = mongoose.model<ISessionDocument, ISessionModel>('Session', SessionSchema);
export default Session;